package com.wdb.modules.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wdb.exception.BadRequestException;
import com.wdb.exception.EntityExistException;
import com.wdb.modules.system.domain.Menu;
import com.wdb.modules.system.domain.Role;
import com.wdb.modules.system.domain.vo.MenuMetaVo;
import com.wdb.modules.system.domain.vo.MenuQueryCriteria;
import com.wdb.modules.system.domain.vo.MenuVo;
import com.wdb.modules.system.mapper.MenuMapper;
import com.wdb.modules.system.mapper.RoleMenuMapper;
import com.wdb.modules.system.service.MenuService;
import com.wdb.modules.system.service.RoleService;
import com.wdb.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: wendaobai@qq.com
 * @date: 2024/1/22 0022 10:28
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
  private final RoleService roleService;
  private final MenuMapper menuMapper;
  private final RoleMenuMapper roleMenuMapper;
  private static final String HTTP_PRE = "http://";
  private static final String HTTPS_PRE = "https://";
  private static final String YES_STR = "是";
  private static final String NO_STR = "否";
  private static final String BAD_REQUEST = "外链必须以http://或者https://开头";

  @Override
  public List<Menu> findByUser(Long currentUserId) {
    // 获取角色列表
    List<Role> roles = roleService.findByUsersId(currentUserId);
    Set<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toSet());
    List<Menu> menus = menuMapper.findByRoleIdsAndTypeNot(roleIds, 2);
    return menus;
  }

  /**
   * 构建树结构
   *
   * @param menuList
   * @return
   */
  @Override
  public List<Menu> buildTree(List<Menu> menus) {
    List<Menu> trees = new ArrayList<>();
    Set<Long> ids = new HashSet<>();
    for (Menu menu : menus) {
      if (menu.getPid() == null) {
        trees.add(menu);
      }
      for (Menu it : menus) {
        if (menu.getId().equals(it.getPid())) {
          if (menu.getChildren() == null) {
            menu.setChildren(new ArrayList<>());
          }
          menu.getChildren().add(it);
          ids.add(it.getId());
        }
      }
    }
    if(trees.isEmpty()){
      trees = menus.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
    }
    return trees;
  }

  @Override
  public List<MenuVo> buildMenus(List<Menu> menus) {
    List<MenuVo> list = new LinkedList<>();
    menus.forEach(menu -> {
              if (menu!=null){
                List<Menu> menuList = menu.getChildren();
                MenuVo menuVo = new MenuVo();
                menuVo.setName(ObjectUtil.isNotEmpty(menu.getComponentName())  ? menu.getComponentName() : menu.getTitle());
                // 一级目录需要加斜杠，不然会报警告
                menuVo.setPath(menu.getPid() == null ? "/" + menu.getPath() :menu.getPath());
                menuVo.setHidden(menu.getHidden());
                // 如果不是外链
                if(!menu.getIFrame()){
                  if(menu.getPid() == null){
                    menuVo.setComponent(StringUtils.isEmpty(menu.getComponent())?"Layout":menu.getComponent());
                    // 如果不是一级菜单，并且菜单类型为目录，则代表是多级菜单
                  }else if(menu.getType() == 0){
                    menuVo.setComponent(StringUtils.isEmpty(menu.getComponent())?"ParentView":menu.getComponent());
                  }else if(StringUtils.isNoneBlank(menu.getComponent())){
                    menuVo.setComponent(menu.getComponent());
                  }
                }
                menuVo.setMeta(new MenuMetaVo(menu.getTitle(),menu.getIcon(),!menu.getCache()));
                if(CollectionUtil.isNotEmpty(menuList)){
                  menuVo.setAlwaysShow(true);
                  menuVo.setRedirect("noredirect");
                  menuVo.setChildren(buildMenus(menuList));
                  // 处理是一级菜单并且没有子菜单的情况
                } else if(menu.getPid() == null){
                  MenuVo menuVo1 = new MenuVo();
                  menuVo1.setMeta(menuVo.getMeta());
                  // 非外链
                  if(!menu.getIFrame()){
                    menuVo1.setPath("index");
                    menuVo1.setName(menuVo.getName());
                    menuVo1.setComponent(menuVo.getComponent());
                  } else {
                    menuVo1.setPath(menu.getPath());
                  }
                  menuVo.setName(null);
                  menuVo.setMeta(null);
                  menuVo.setComponent("Layout");
                  List<MenuVo> list1 = new ArrayList<>();
                  list1.add(menuVo1);
                  menuVo.setChildren(list1);
                }
                list.add(menuVo);
              }
            }
    );
    return list;
  }

  @Override
  public List<Menu> queryAll(MenuQueryCriteria criteria, boolean isQuery)
      throws IllegalAccessException {
    if (Boolean.TRUE.equals(isQuery)) {
      criteria.setPidIsNull(true);
      // 包含了查询条件的接口，返回顶级菜单列表
      List<Field> fields = StringUtils.getAllFields(criteria.getClass(), new ArrayList<>());
      for (Field field : fields) {
        field.setAccessible(true);
        Object val = field.get(criteria);
        if ("pidIsNull".equals(field.getName())) {
          continue;
        }
        if (ObjectUtil.isNotNull(val)) {
          criteria.setPidIsNull(null);
          break;
        }
      }
    }
    return menuMapper.findAll(criteria);
  }

  @Override
  public List<Menu> getMenus(Long pid) {
    List<Menu> menus = null;
    if (pid != null && !pid.equals(0L)) {
      menus = menuMapper.findByPidOrderByMenuSort(pid);
    } else {
      menus = menuMapper.findByPidIsNullOrderByMenuSort();
    }

    return menus;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void create(Menu resources) {
    // 菜单名称查重
    if (menuMapper.findByTitle(resources.getTitle()) != null) {
      throw new EntityExistException(Menu.class, "title", resources.getTitle());
    }
    // 组件名称查重
    if (StringUtils.isNotBlank(resources.getComponentName())) {
      if (menuMapper.findByComponentName(resources.getComponentName()) != null) {
        throw new EntityExistException(Menu.class, "componentName", resources.getComponentName());
      }
    }
    // pid 0  赋值为null
    if (Long.valueOf(0L).equals(resources.getPid())) {
      resources.setPid(null);
    }
    // 设置子节点数量
    resources.setSubCount(0);
    // 保存菜单
    save(resources);

    // 跟新父节点的数量
    updateSubCnt(resources.getPid());
  }

  @Override
  /** 查询所有子菜单 */
  public void getChildMenus(List<Menu> menuList, Set<Menu> menuSet) {
    for (Menu menu : menuList) {
      menuSet.add(menu);
      List<Menu> list = getMenus(menu.getId());
      if (list != null && list.size() > 0) {
        getChildMenus(list, menuSet);
      }
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void delete(Set<Menu> menuSet) {
    for (Menu menu : menuSet) {
      // 清除缓存
      // 删除  menu表 与 role_menu表
      roleMenuMapper.deleteByMenuId(menu.getId());
      menuMapper.deleteById(menu.getId());
      updateSubCnt(menu.getPid());
    }
  }

  @Override
  public List<Menu> getSuperior(Menu menu, List<Menu> menus) {
    if (menu.getPid() == null) {
      menus.addAll(menuMapper.findByPidIsNullOrderByMenuSort());
      return menus;
    }
    menus.addAll(menuMapper.findByPidOrderByMenuSort(menu.getPid()));
    return getSuperior(findById(menu.getPid()), menus);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void update(Menu resources) {
    log.info("xxx--{}",resources);
    // 检查上级节点是否为自己，避免循环引用或自引用的情况
    if (resources.getId().equals(resources.getPid())) {
      throw new BadRequestException("上级不能为自己");
    }
    // 根据资源ID查询对应的菜单或资源信息
    Menu menu = getById(resources.getId());
    // 如果资源是一个内嵌框架（IFrame），则需要检查其路径是否符合HTTP或HTTPS协议格式
    if (resources.getIFrame()) {
      if (!resources.getPath().toLowerCase().startsWith(HTTP_PRE)
          || !resources.getPath().toLowerCase().startsWith(HTTPS_PRE)) {
        throw new BadRequestException(BAD_REQUEST);
      }
    }
    Menu menuMapperByTitle = menuMapper.findByTitle(resources.getTitle());
    if (menuMapperByTitle != null && !menuMapperByTitle.getId().equals(resources.getId())) {
      throw new EntityExistException(Menu.class, "title", resources.getTitle());
    }
    if (StringUtils.isNotBlank(resources.getComponentName())) {
      Menu menuMapperByComponentName = menuMapper.findByComponentName(resources.getComponentName());
      if (menuMapperByComponentName != null
          && !menuMapperByComponentName.getId().equals(resources.getId())) {
        throw new EntityExistException(Menu.class, "componentName", resources.getComponentName());
      }
    }
    // pid 是0 则pid为null
    if (resources.getPid().equals(0L)) {
      resources.setPid(null);
    }
    // 保存菜单
    saveOrUpdate(resources);
    // 计算父级菜单节点数目
    updateSubCnt(menu.getPid());
    updateSubCnt(resources.getPid());

  }

  @Override
  public Menu findById(long id) {
    return getById(id);
  }

  /**
   * 更新 字节点数量
   *
   * @param id
   */
  private void updateSubCnt(Long id) {
    int subCount = menuMapper.countByPid(id);
    menuMapper.updateSubCntById(id, subCount);
  }
}
